package com.ch.mobilesha.img;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.widget.ImageView;

import com.ch.mobilesha.common.HttpClientUtils;

/**
 * 异步加载图片并进行缓存
 * 
 * @author liuweixiang
 * 
 */
public class PictrueManager {
	private static final String LOG_TAG = "PictrueManager";

	private int DELAY_BEFORE_PURGE = 30 * 1000; // in milliseconds
	private PictureCache cache = new PictureCache("image/");

	private Context mContext;

	public PictrueManager(Context context) {
		this.mContext = context;
	}

	private final Handler purgeHandler = new Handler();

	private final Runnable purger = new Runnable() {
		public void run() {
			clearCache();
		}
	};

	// private static void recycleBitmap(Bitmap bitmap) {
	// if(bitmap != null && !bitmap.isRecycled()) {
	// Log.i(LOG_TAG, "recycleBitmap, bitmap == null");
	// bitmap.recycle();
	// bitmap = null;
	// }
	// }

	public static void clearTempCache() {
		// if(sTempBitmapCache != null && sTempBitmapCache.size() > 0) {
		// Set<Entry<String, Bitmap>> entrySet = sTempBitmapCache.entrySet();
		// for (Entry<String, Bitmap> entry : entrySet) {
		// recycleBitmap(entry.getValue());
		// }
		// sTempBitmapCache.clear();
		// }

	}

	/**
	 * 异步获取图片
	 * 
	 * @param url
	 *            图片地址
	 * @param imageView
	 *            图片显示控件
	 */
	public void download(String url, ImageView imageView) {
		download(url, imageView, -1000);
	}

	/**
	 * 异步获取图片
	 * 
	 * @param url
	 *            图片地址
	 * @param imageView
	 *            图片显示控件
	 * @param resId
	 *            背景
	 */
	public void download(String url, ImageView imageView, int resId) {
		if (url == null)
			return;
		Bitmap bitmapBg = null;
		if (resId != -1000)
			bitmapBg = BitmapFactory.decodeResource(mContext.getResources(), resId);
		resetPurgeTimer();
		Bitmap bitmap = getBitmapFromCache(url);
		if (bitmap == null) {
			forceDownload(url, imageView, bitmapBg);
		} else {
			cancelPotentialDownload(url, imageView);
			imageView.setImageBitmap(bitmap);
		}
		// Log.w(LOG_TAG, "map.size " + sHardBitmapCache.size() + "/" +
		// sTempBitmapCache.size());
	}

	/**
	 * 根据key值删除图片
	 * 
	 * @param key
	 */
	public void removeBitmap(String key) {
		if (cache.containsKey(key)) {
			cache.remove(key);
		}
	}

	/**
	 * 添加图片
	 * 
	 * @param key
	 * @param value
	 */
	public void addBitmap(String key, Bitmap value) {
		cache.put(key, value);
	}

	private void forceDownload(String url, ImageView imageView, Bitmap bitmapBg) {
		if (url == null) {
			imageView.setImageDrawable(null);
			return;
		}
		if (cancelPotentialDownload(url, imageView)) {
			BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
			DownloadedBitmap downloadedDrawable = new DownloadedBitmap(task, bitmapBg);
			imageView.setImageDrawable(downloadedDrawable);
			task.execute(url);
		}
	}

	public void clearCache() {
		cache.clearMemoryCache();
	}

	private void resetPurgeTimer() {
		purgeHandler.removeCallbacks(purger);
		purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);
	}

	private static boolean cancelPotentialDownload(String url, ImageView imageView) {
		BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

		if (bitmapDownloaderTask != null) {
			String bitmapUrl = bitmapDownloaderTask.url;
			if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
				bitmapDownloaderTask.cancel(true);
			} else {
				return false;
			}
		}
		return true;
	}

	private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
		if (imageView != null) {
			Drawable drawable = imageView.getDrawable();
			if (drawable instanceof DownloadedBitmap) {
				DownloadedBitmap downloadedDrawable = (DownloadedBitmap) drawable;
				return downloadedDrawable.getBitmapDownloaderTask();
			}
		}
		return null;
	}

	public Bitmap getBitmapFromCache(String url) {
		return cache.get(url);
	}

	class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
		private static final int IO_BUFFER_SIZE = 4 * 1024;
		private String url;
		private final WeakReference<ImageView> imageViewReference;

		public BitmapDownloaderTask(ImageView imageView) {
			imageViewReference = new WeakReference<ImageView>(imageView);
		}

		@Override
		protected Bitmap doInBackground(String... params) {

			url = params[0];
			final DefaultHttpClient client = HttpClientUtils.getHttpClient();
			HttpGet getRequest = null;
			try {
				// final AndroidHttpClient client =
				// AndroidHttpClient.newInstance("Android");
				getRequest = new HttpGet(url);
				HttpResponse response = client.execute(getRequest);
				final int statusCode = response.getStatusLine().getStatusCode();
				if (statusCode != HttpStatus.SC_OK) {
					return null;
				}
				final HttpEntity entity = response.getEntity();
				if (entity != null) {
					InputStream inputStream = null;
					OutputStream outputStream = null;
					FileInputStream fis = null;
					try {
						inputStream = entity.getContent();
						final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
						outputStream = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
						copy(inputStream, outputStream);
						outputStream.flush();

						final byte[] data = dataStream.toByteArray();

						// BitmapFactory.Options opts = new
						// BitmapFactory.Options();
						// opts.inJustDecodeBounds = true;
						// BitmapFactory.decodeByteArray(data, 0, data.length,
						// opts);
						// opts.inSampleSize = computeSampleSize(opts, -1,
						// 128*128);
						// //这里一定要将其设置回false，因为之前我们将其设置成了true
						// opts.inJustDecodeBounds = false;
						// if(fis != null) {
						// BitmapFactory.Options opts = new
						// BitmapFactory.Options();
						// opts.inDither = false;
						// opts.inPurgeable = true;
						// opts.inTempStorage = new byte[100 * 1024];
						// return
						// BitmapFactory.decodeFileDescriptor(fis.getFD(), null,
						// opts);
						// } else

						// if(data.length > 20000) {
						// BitmapFactory.Options opts = new
						// BitmapFactory.Options();
						// opts.inSampleSize = 2;
						// final Bitmap bitmap =
						// BitmapFactory.decodeByteArray(data, 0, data.length,
						// opts);
						// if (bitmap != null) {
						// return bitmap;
						// }
						// } else {
						final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
						if (bitmap != null) {
							cache.put(url, bitmap);
							return bitmap;
						}
						// }
						// return BitmapFactory.decodeByteArray(data, 0,
						// data.length);
					} finally {
						if (fis != null) {
							fis.close();
						}
						if (inputStream != null) {
							inputStream.close();
						}
						if (outputStream != null) {
							outputStream.close();
						}
						entity.consumeContent();
					}
				}
			} catch (IOException e) {
				if (getRequest != null) {
					getRequest.abort();
				}
			} catch (IllegalStateException e) {
				if (getRequest != null) {
					getRequest.abort();
				}
			} catch (Exception e) {
				if (getRequest != null) {
					getRequest.abort();
				}
			} finally {
				// if (client != null) {
				// client.close();
				// }
			}
			return null;
		}

		@Override
		protected void onPostExecute(Bitmap bitmap) {
			if (isCancelled()) {
				bitmap = null;
			}

			if (bitmap != null && imageViewReference != null) {
				ImageView imageView = imageViewReference.get();
				BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
				if (this == bitmapDownloaderTask) {
					imageView.setImageBitmap(bitmap);
				}
			}
		}

		public void copy(InputStream in, OutputStream out) throws IOException {
			byte[] b = new byte[IO_BUFFER_SIZE];
			int read;
			while ((read = in.read(b)) != -1) {
				out.write(b, 0, read);
			}
		}
	}

	static class DownloadedDrawable extends ColorDrawable {
		private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
		final Drawable drawable;

		public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask, Drawable drawable) {
			this.drawable = drawable;
			bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
		}

		public BitmapDownloaderTask getBitmapDownloaderTask() {
			return bitmapDownloaderTaskReference.get();
		}
	}

	static class DownloadedBitmap extends BitmapDrawable {
		private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

		public DownloadedBitmap(BitmapDownloaderTask bitmapDownloaderTask, Bitmap bitmap) {
			super(bitmap);
			bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
		}

		public BitmapDownloaderTask getBitmapDownloaderTask() {
			return bitmapDownloaderTaskReference.get();
		}
	}

	public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}
		return roundedSize;
	}

	private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;
		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
		if (upperBound < lowerBound) {
			return lowerBound;
		}
		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}

	public PictrueManager() {
	}
}